/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

// 圆球
import { KEYBOARD_KEY } from '@app-cad/common/Constants';
import { wsApi } from '@app-cad/server';
import i18n from 'i18next';
import { useEffect } from 'react';
import { Vector3 } from 'three-legacy';

import {
  BaseCommand,
  CadScene,
  CENTEREVENTS,
  CSCircle,
  CSLine,
  css2dInputLable,
  MathTool,
  SceneGraph,
  useStore,
} from '@amcax/base';
import { eventCenterManager } from '@app-base/common/events/EventCenterManager';
import { ctx2 } from '@app-cad/module';

enum State {
  NONE,
  DRAW,
  FINISH,
}

type MouseState = State.NONE | State.DRAW | State.FINISH;

interface TrackingData {
  circle: CSCircle;
  rLine: CSLine;
  rLabel: css2dInputLable;
}

interface SphereCommandProps {
  title: string;
  onClose: () => void;
}

function SphereCommand({ onClose }: SphereCommandProps) {
  const updateCmdHighlightId = useStore((state) => state.updateCmdHighlightId);
  const cadScene = ctx2.cadScene as CadScene;
  const sceneSetup = ctx2.viewer.sceneSetup;
  const assisGroup = cadScene.assisGroup;
  // 固定为 XOY 平面
  const planeNormal: Vector3 = new Vector3(0, 0, 1);
  const planeOrigin: Vector3 = new Vector3(0, 0, 0);
  let startPoint: Vector3; // 绘制起点：圆心
  let endPoint: Vector3; // 绘制终点 ：圆上的某个点
  let radius: number = 0; // 圆半径

  let currentStatus: MouseState = State.NONE; // 记录当前状态

  const trackingData: TrackingData = {
    circle: null,
    rLine: null,
    rLabel: null,
  };

  useEffect(() => {
    // enter
    // setPickMode(['sketch']) // ["face", "edge", "vertex", "shell"]
    eventCenterManager.activeEventCenter
      .setState('sphere')
      .on(CENTEREVENTS.KEYUP, onKeyUp)
      .addExit(onDestroy);
    init();

    return onDestroy;
  }, []);

  const init = () => {
    registerEvents();
  };
  const onDestroy = () => {
    // setPickMode(['shell'])
    eventCenterManager.activeEventCenter
      .off(CENTEREVENTS.KEYUP, onKeyUp)
      .setDefault();
    unregisterEvents();
    releaseObjects();
    onClose();
  };

  const onKeyUp = (e) => {
    if (e.event.key === KEYBOARD_KEY.ESC) {
      onDestroy();
    }
  };

  // ========= 鼠标和键盘事件=========
  const canvas = ctx2.container;
  const registerEvents = () => {
    document.addEventListener('keyup', onKeyup);
    canvas.addEventListener('mouseup', onMouseClick);
    eventCenterManager.activeEventCenter.on(
      CENTEREVENTS.POINTERMOVE,
      onMouseMove,
    );
  };
  const unregisterEvents = () => {
    document.removeEventListener('keyup', onKeyup);
    canvas.removeEventListener('mouseup', onMouseClick);
    eventCenterManager.activeEventCenter.off(
      CENTEREVENTS.POINTERMOVE,
      onMouseMove,
    );
  };

  const onKeyup = (e: KeyboardEvent) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      onDestroy();
    } else if (e.key === KEYBOARD_KEY.ENTER) {
      if (currentStatus === State.DRAW) {
        finishDraw();
        onDestroy();
      }
    }
  };
  const onMouseClick = (e: any) => {
    if (e.button === 0) {
      if (currentStatus === State.NONE) {
        trackingData.circle = null;
        // 鼠标左键，开始绘制圆心
        startPoint = sceneSetup.mouseOnPlane(
          e.layerX,
          e.layerY,
          planeNormal,
          planeOrigin,
        );
        currentStatus = State.DRAW;
      } else if (currentStatus === State.DRAW) {
        finishDraw();
        onDestroy();
      }
    } else if (e.button === 2) {
      currentStatus = State.FINISH;
      // 鼠标右键，取消
      onDestroy();
    }
  };
  const onMouseMove = (e: any) => {
    if (currentStatus === State.DRAW) {
      endPoint = sceneSetup.mouseOnPlane(
        e.event.layerX,
        e.event.layerY,
        planeNormal,
        planeOrigin,
      );
      radius = startPoint.clone().sub(endPoint).length();
      preview();
    }
  };
  // ========= 鼠标和键盘事件 =========
  const finishDraw = async () => {
    if (radius != 0) {
      const params = {
        radius: radius,
      };
      await wsApi.createPrimitive('Sphere', params, [
        [startPoint.x, startPoint.y, 0],
        [0, 0, 1],
        [1, 0, 0],
      ]);
    }
  };

  // 释放对象
  const releaseObjects = () => {
    trackingData.circle && trackingData.circle.destroy();
    trackingData.rLine && trackingData.rLine.destroy();
    trackingData.rLabel && trackingData.rLabel.destroy();

    assisGroup.clear();
    SceneGraph.emptyGroup(assisGroup);
    ctx2.viewer.requestRender();

    updateCmdHighlightId('');
  };

  const preview = () => {
    if (currentStatus === State.DRAW) {
      // 绘制圆
      if (!trackingData.circle) {
        if (!trackingData.circle) {
          trackingData.circle = new CSCircle({
            center: startPoint,
            radius: radius,
            csys: MathTool.createCsysFromPlacement([
              [startPoint.x, startPoint.y, 0],
              [0, 0, 1],
              [1, 0, 0],
            ]),
            lineWidth: 2,
          });
        }
        trackingData.circle.addTo(assisGroup);
      } else {
        trackingData.circle.update({ radius: radius });
      }

      // 绘制圆半径
      if (!trackingData.rLine) {
        trackingData.rLine = new CSLine({
          vertexs: [
            new Vector3(startPoint.x, startPoint.y, 0),
            new Vector3(endPoint.x, endPoint.y, 0),
          ],
          dashed: true,
          lineWidth: 1,
          depthTest: true,
        });
        trackingData.rLine.addTo(assisGroup);
      } else {
        trackingData.rLine.setVertexs([
          new Vector3(startPoint.x, startPoint.y, 0),
          new Vector3(endPoint.x, endPoint.y, 0),
        ]);
      }

      // draw input label
      const labelText = startPoint.distanceTo(endPoint);
      const labelPos = new Vector3();
      labelPos.x = (startPoint.x + endPoint.x) / 2;
      labelPos.y = (startPoint.y + endPoint.y) / 2;
      labelPos.z = (startPoint.z + endPoint.z) / 2;
      if (!trackingData.rLabel) {
        trackingData.rLabel = new css2dInputLable({
          text: labelText,
          position: labelPos,
        });
        trackingData.rLabel.focus();
        trackingData.rLabel.addTo(assisGroup);
      } else {
        trackingData.rLabel.update(labelText, labelPos);
      }
      ctx2.viewer.requestRender();
    }
  };
  return null;
}

export const cmdSphere: BaseCommand = {
  id: 'CmdSphere',
  label: 'command.sphere',
  icon: 'commands/feature/sphere',
  create: (label: string, onClose: () => void) => (
    <SphereCommand
      title={i18n.t(label)}
      onClose={onClose}
    />
  ),
};
